<template>
  <el-dialog title="流程表单设计" :visible.sync="dialogVisible" :fullscreen="true" :lock-scroll="true"
    :destroy-on-close="true" v-loading="dataLoad" element-loading-text="加载中" id="mydialog">
      
    <el-row :gutter="0" style="background-color: #ffffff;">
      <el-col :span="10" :offset="1">
        <el-card shadow="always" :body-style="{ padding: '20px', }" v-loading="flowLoading" 
          element-loading-text="请完成左边修改">
          <!-- style="height: 78vh;overflow-y: scroll;" -->
          <div slot="header">
            <span>流程设计</span>
          </div>
          <!-- card body -->
          <el-row v-for="(step, stepIndex) in flowData" :key="stepIndex">
            <el-col v-for="(item, itemIndex) in step" :key="itemIndex" :span="24 / step.length">
              <el-card shadow="always" :body-style="{ padding: '20px' }" :class="'card ' + nodeClassType[item.type]"
                :id="item.id" v-loading="item.loading">
                <div slot="header">
                  <span class="titleType" v-if="item.type == '0' || item.type == '1'">[{{ nodeTitleType[item.type]
                  }}]-</span>
                  <span>{{ item.name }}</span>
                  <el-button style="float: right; padding: 3px 0; color:#ffffff;margin-left: 20px;" type="text"
                    v-if="item.type != '2'" @click="deleteNode(item, stepIndex, itemIndex)">删除
                  </el-button>
                  <el-button style="float: right; padding: 3px 0; color:#ffffff;margin-left: 20px;"
                    v-if="item.type != '3' && item.type != '2'" type="text" @click="editNode(item, stepIndex, itemIndex)">编辑
                  </el-button>
                  <el-button style="float: right; padding: 3px 0; color:#ffffff" type="text"
                    v-if="item.type != '3' && item.type != '1'" @click="addNode(item, stepIndex, itemIndex)">添加节点
                  </el-button>
                </div>
                <!-- card body -->
                <div v-if="item.type == '2'">可发起人/部门/职位/:{{ item.people }}</div>
                <div>{{ item.id }}</div>
                <div v-if="item.type=='0'">
                  <!-- 审核节点显示内容 -->
                  <div>审核模式：{{ item.auditMode=='0'?"全部通过审核":item.sendOther?"一人通过即可（抄送其他审核人）":"一人通过即可" }}</div> 
                  <div>审核人信息：</div>
                  <div>
                    <span v-for="auditId in item.auditUsers" :key="auditId">{{ getUseName(auditId)+' ' }}</span>
                  </div>
                  <div>自动添加部门领导：{{ item.addDepartmentLeader | fmtTF }}</div>
                  <div>自动添加直接上级：{{ item.addJobLeader | fmtTF }}</div>
                </div>
              </el-card>
            </el-col>
          </el-row>
        </el-card>
        <el-button type="primary" @click="onSubmit">保 存</el-button>
      </el-col>

      <el-col :span="10" :offset="2">
        <!-- style="height: 82vh;overflow-y: scroll;" -->
        <el-card shadow="always" :body-style="{ padding: '20px 30px', }" >
          <div slot="header">
            <span>设置</span>
          </div>
          <!-- card body -->
          <el-form label-width="110px" :inline="false" size="normal" :disabled="nowIndex.length == 0">
            <el-divider content-position="left">条件</el-divider>

            <el-form-item label="上一节点:" size="normal">
              {{ linkForm.lastNodeText }}
            </el-form-item>

            <el-form-item label="前置条件:">
              <el-radio v-model="linkForm.operation" :label="2" :disabled="!operationRule.start || editMode">开始</el-radio>
              <el-radio v-model="linkForm.operation" :label="0" :disabled="!operationRule.agree || editMode">同意</el-radio>
              <el-radio v-model="linkForm.operation" :label="1" :disabled="!operationRule.reject || editMode">拒绝</el-radio>
            </el-form-item>
            <div v-if="linkForm.operation == '0' || linkForm.operation == '2'">
              <el-divider content-position="left">下一节点</el-divider>
              <el-form-item label="节点类型:">
                <el-select v-model="form.type" placeholder="请选择节点类型" clearable filterable class="select100">
                  <el-option label="审核" value="0"></el-option>
                  <el-option label="抄送" value="1"></el-option>
                  <el-option label="结束" value="3"></el-option>
                </el-select>
              </el-form-item>
              <el-form-item label="节点名称" size="normal" v-if="form.type != '3'">
                <el-input v-model="form.name" placeholder="请输入节点名称" size="normal" clearable></el-input>
              </el-form-item>
              <div class="aduitInfo" v-if="form.type == '0'">
                <el-form-item label="指定审核人" size="normal">
                  <el-select v-model="form.auditUsers" multiple placeholder="请选择" class="select100">
                    <el-option v-for="item in selectOptions.user" :key="item.id" :label="item.name"
                      :value="item.id"></el-option>
                  </el-select>
                </el-form-item>
                <el-form-item label="添加部门领导" size="normal">
                  <el-radio v-model="form.addDepartmentLeader" :label="true">是</el-radio>
                  <el-radio v-model="form.addDepartmentLeader" :label="false">否</el-radio>
                </el-form-item>
                <el-form-item label="添加直接上级" size="normal">
                  <el-radio v-model="form.addJobLeader" :label="true">是</el-radio>
                  <el-radio v-model="form.addJobLeader" :label="false">否</el-radio>
                </el-form-item>
                <el-form-item label="审核模式" size="normal">
                  <el-radio v-model="form.auditMode" label="0">需全部人员通过</el-radio>
                  <el-radio v-model="form.auditMode" label="1">一人通过即可</el-radio>
                </el-form-item>
                <el-form-item label="抄送其他审核人" size="normal" v-if="form.auditMode == '1'">
                  <el-radio v-model="form.sendOther" :label="true">是</el-radio>
                  <el-radio v-model="form.sendOther" :label="false">否</el-radio>
                </el-form-item>
              </div>

              <div class="sendMsg" v-if="form.type == '1'">
                <el-form-item label="抄送人" size="normal">
                  <el-select v-model="form.auditUsers" multiple filterable placeholder="请选择" class="select100">
                    <el-option v-for="item in selectOptions.user" :key="item.id" :label="item.name"
                      :value="item.id"></el-option>
                  </el-select>
                </el-form-item>
              </div>
            </div>

            <div class="reject" v-if="linkForm.operation == '1'">
              <el-form-item label="后续操作" size="normal">
                <!-- <el-select v-model="form.rejectOperation" placeholder="请选择拒绝后的操作" filterable class="select100">
                  <el-option label="回退" value="1"></el-option>
                  <el-option label="结束流程" value="2"></el-option>
                </el-select> -->

                <el-radio-group v-model="form.rejectOperation" >
                  <el-radio v-model="form.rejectOperation" :label="1">回退</el-radio>
                  <el-radio v-model="form.rejectOperation" :label="2">结束流程</el-radio>
                </el-radio-group>
              </el-form-item>

            </div>

            <el-form-item>
              <el-button type="primary" @click="saveNode" v-if="!editMode" :disabled="nowIndex.length == 0">立即创建</el-button>
              <el-button type="primary" @click="editNodeSave" v-if="editMode" :disabled="nowIndex.length == 0">保存修改</el-button>
              <el-button @click="formCancel">取消</el-button>
            </el-form-item>
          </el-form>

        </el-card>
      </el-col>
    </el-row>
  </el-dialog>
</template>

<script>
import LeaderLine from 'leader-line'
import GUID from '@/utils/guid'
import { getSelect as getUserSelect } from "@/api/user/user"
import { deepClone } from "@/utils/deepClone"
import { getFlowDesign,insertFlowDesign } from "@/api/workFlowTemplate/workFlowTemplate"

// 用于保存绘制的箭头，不知道为什么不能保存在vue的data中
var lines = []

export default {
  async created() {
    await this.loadUserSelect()
    await this.loadFlowDisegn()
  },
  mounted(){
    this.$nextTick(()=>{
      let h = document.getElementsByClassName('el-dialog')[0]
      h.addEventListener("scroll", this.scrolling)
    });

  },
  props: {
    value: Boolean,
    workFlowId: String,
  },
  data() {
    return {
      dataLoad:true,
      editMode:false,
      dialogVisible: this.value,
      form: {
        id: '',
        name: '',
        type: '',
        addDepartmentLeader: 'false',
        addJobLeader: 'false',
        auditMode: '0',
        sendOther: 'false',
        auditUsers: [],
        rejectOperation: '',
      },
      linkForm: {
        nextNode: '',
        lastNode: '',
        lastNodeText: '',
        operation: ''
      },
      flowLoading: false,
      lineOptions: {
        startSocket: 'bottom',
        endSocket: 'top',
        path: 'grid',
        color: '#606266',
        size: 2
      },
      flowData: [],
      nodeLinks: [],
      selectOptions: {
        user: []
      },
      nodeClassType: ['audit', 'carbonCopy', 'start', 'end'],
      nodeTitleType: ['审核', '抄送', '开始', '结束'],
      nodeLinkOperation: ['同意', '拒绝', '开始', '结束'],
      operationRule: {
        start: true,
        agree: true,
        reject: true,
        end: true
      },
      nowIndex: [],
      needDeletNode: []
    }
  },
  filters:{
    fmtTF(value){
      return value?"是":"否"
    }
  },
  computed:{
    getUseName(){
      return function(uid){
        return this.selectOptions.user.filter(r=>r.id==uid)[0].name
      }
    }
  },
  watch: {
    dialogVisible(val) {
      this.$emit('input', val)
    },
    value(val) {
      this.dialogVisible = val
    }
  },
  beforeDestroy() {
    this.clearLines()
  },
  methods: {
    async loadUserSelect() {
      let res = await getUserSelect()
      if (res.code == 10000) {
        this.selectOptions.user = res.data
      }
    },
    async loadFlowDisegn(){
      this.dataLoad = false
      let res = await getFlowDesign(this.workFlowId)
      if(res.code == 10000){
        this.flowData = res.data.nodeList
        this.nodeLinks = res.data.linkList
      }
      
      this.$nextTick(() => {
        this.drawLine()
      })
    },
    scrolling(){
      for (let i = 0; i < lines.length; i++) {
        let item = lines[i];
        item.position()
      }
    },
    clearLines() {
      for (let i = 0; i < lines.length; i++) {
        let item = lines[i];
        item.remove()
      }
      lines = []
    },
    drawLine() {
      this.clearLines()
      for (let index = 0; index < this.nodeLinks.length; index++) {
        let item = this.nodeLinks[index];

        let start = document.getElementById(item.lastNode)
        let end = document.getElementById(item.nextNode)

        let line = new LeaderLine(start, end, this.lineOptions)
        if (item.operation == '1') {
          let itemIndex = this.findNodeItemIndex(item.lastNode)
          line.setOptions({
            startSocket: itemIndex == 1 ? 'right' : 'left',
            endSocket: itemIndex == 1 ? 'right' : 'left',
            color: 'red'
          })
        }
        if (item.operation == '3') {
          line.setOptions({
            color: 'red'
          })
        }
        line.endLabel = LeaderLine.captionLabel(this.nodeLinkOperation[item.operation])
        lines.push(line)
      }
    },
    editNode(item, stepIndex, itemIndex){
      this.resetForm()
      this.editMode = true
      this.form = deepClone(item)
      this.nowIndex.push(stepIndex) 
      this.nowIndex.push(itemIndex)

      let link = this.nodeLinks.find(r=>r.nextNode == item.id)
      this.linkForm.lastNode = link.lastNode
      this.linkForm.nextNode = link.nextNode
      this.linkForm.operation = link.operation
      this.linkForm.lastNodeText = this.getNodeById(link.lastNode).name
    },
    editNodeSave(){
      this.$set(this.flowData[this.nowIndex[0]],this.nowIndex[1],deepClone(this.form))
      this.$message({
        type:"success",
        message:"修改成功"
      })
      this.editMode = false
      this.formCancel()
    },
    getNodeById(nodeId){
      for (let index = 0; index < this.flowData.length; index++) {
        const step = this.flowData[index];
        for (let j = 0; j < step.length; j++) {
          const item = step[j];
          if (item.id == nodeId) {
            return item
          }
        }
      }
    },
    addNode(node, stepIndex, itemIndex) {
      this.linkForm.lastNodeText = node.name
      this.linkForm.lastNode = node.id
      this.form.id = GUID.newGuid()
      if (node.type == 2) {
        // 开始节点 只能选择开始
        this.operationRule.agree = false
        this.operationRule.reject = false
        this.operationRule.end = false
        this.operationRule.start = true
      } else {
        this.operationRule.agree = true
        this.operationRule.reject = true
        this.operationRule.end = true
        this.operationRule.start = false
      }
      // 加载动画
      this.nodeLoadingStart(node.id)

      this.nowIndex[0] = stepIndex
      this.nowIndex[1] = itemIndex
    },
    /**
     * 开始加载动画，增加页面聚焦能力
     * @param {strin} nodeId 不加载动画的节点
     */
    nodeLoadingStart(nodeId) {
      for (let i = 0; i < this.flowData.length; i++) {
        const step = this.flowData[i];
        for (let j = 0; j < step.length; j++) {
          let item = step[j];
          if (item.id != nodeId) {
            item.loading = true
          }
        }
      }
    },
    nodeLoadingEnd() {
      for (let i = 0; i < this.flowData.length; i++) {
        const step = this.flowData[i];
        for (let j = 0; j < step.length; j++) {
          let item = step[j];
          item.loading = false
        }
      }
    },
    deleteNode(item) {
      this.$confirm('是否确定删除该节点?若该节点有后续节点将会一并删除！', '提示', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning'
      }).then(() => {
        this.needDeletNode = []
        // 删除连接Node
        this.deleteLink(item.id)
        // 删除节点
        let deleteIds = [...new Set(this.needDeletNode)]
        let deleteNodeIndex = []
        for (let j = 0; j < deleteIds.length; j++) {
          const deleteId = deleteIds[j];
          for (let i = 0; i < this.flowData.length; i++) {
            let step = this.flowData[i];
            let index = step.findIndex(r => r.id == deleteId)
            if (index > -1) {
              deleteNodeIndex.push([i, index])
            }
          }
        }
        for (let i = 0; i < deleteNodeIndex.length; i++) {
          const item = deleteNodeIndex[i];
          this.flowData[item[0]].splice(item[1], 1)
        }

        this.$message({
          type: 'success',
          message: '删除成功!'
        })
        this.resetForm()
        this.$nextTick(() => {
          this.drawLine()
        })
      }).catch(() => {

      });
    },
    /** 通过节点ID获取节点当前层级中的索引 用于判断节点在右侧还是左侧 */
    findNodeItemIndex(nodeId) {
      for (let index = 0; index < this.flowData.length; index++) {
        const step = this.flowData[index];
        for (let j = 0; j < step.length; j++) {
          const item = step[j];
          if (item.id == nodeId) {
            return j;
          }
        }
      }
    },
    saveNode() {
      // todo 表单验证
      let key = this.form.id

      if (this.linkForm.operation != '1') {
        
        if(this.form.type == '3')
          this.form.name = "结束"

        let data = deepClone(this.form);
        this.linkForm.nextNode = key
        data.loading = false
        let stepIndex = this.nowIndex[0] + 1
        if (typeof (this.flowData[stepIndex]) == "undefined") {
          this.$set(this.flowData, stepIndex, [])
        }
        else if (this.flowData[stepIndex].length > 0) {
          if (this.flowData[stepIndex][0].type === this.form.type) {
            this.$message({
              message: '不能存在两个相同类型节点',
              type: 'warning',
              duration: 7000
            })
            return
          }

          if (this.flowData[stepIndex].length > 1) {
            this.$message({
              message: '最多两个子节点，如需并行或串行，请于审核节点进行设置',
              type: 'warning',
              duration: 7000
            })
            return
          }
        }

        this.flowData[stepIndex].push(data)
      }
      else {
        this.linkForm.nextNode = this.flowData[0][0].id
        this.flowData[this.nowIndex[0]][this.nowIndex[1]].rejectOperation = this.form.rejectOperation
      }

      let link = deepClone(this.linkForm)
      this.nodeLinks.push(link)
      this.nodeLoadingEnd()
      this.$nextTick(() => {
        this.drawLine()
      })

      this.resetForm()
    },
    resetForm() {
      this.form = {
        id: '',
        name: '',
        type: '',
        addDepartmentLeader: false,
        addJobLeader: false,
        auditMode: '0',
        sendOther: false,
        auditUsers: [],
        rejectOperation: '',
      }
      this.linkForm = {
        nextNode: '',
        lastNode: '',
        lastNodeText: '',
        operation: ''
      }

      this.nowIndex = []
    },
    deleteLink(nodeId) {
      let index = this.nodeLinks.findIndex(r => r.lastNode == nodeId || r.nextNode == nodeId)
      if (index == -1) {
        return
      }
      let item = this.nodeLinks[index]
      this.nodeLinks.splice(index, 1)
      this.needDeletNode.push(nodeId)
      this.deleteLink(nodeId)
      if (item.lastNode == nodeId) {
        if (item.nextNode != this.flowData[0][0].id) {
          this.needDeletNode.push(item.nextNode)
          this.deleteLink(item.nextNode)
        }

      }
    },
    formCancel() {
      // 取消 清空表单，取消聚焦动画
      this.resetForm()
      this.nodeLoadingEnd()
    },
    async onSubmit(){
      let data = {
        workFlowId : this.workFlowId,
        links : this.nodeLinks,
        nodes : this.flowData
      }
      let result = await insertFlowDesign(data)
      if (result.code==10000) {
        this.$message({
          type:'success',
          message:'保存成功'
        })
        this.dialogVisible = false
      }
    }

  }
}

</script>

<style scoped>
.card {
  margin: 20px 10px;
  margin-bottom: 50px;
}

.titleType {
  font-weight: bolder;
}

.el-card ::v-deep.start .el-card__header {
  background-color: #67C23A;
  color: #fff
}

.el-card ::v-deep.audit .el-card__header {
  background-color: #409EFF;
  color: #fff
}

.el-card ::v-deep.carbonCopy .el-card__header {
  background-color: #E6A23C;
  color: #fff
}

.el-card ::v-deep.end .el-card__header {
  background-color: #F56C6C;
  color: #fff
}


</style>